package com.signcomplex.nettyandroid;

import android.os.Handler;
import android.os.Message;

import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

public class TimeClient {

    // 配置客户端NIO线程组
    private volatile EventLoopGroup workerGroup;
    private volatile Bootstrap bootstrap;

    private volatile boolean closed = false;

    private int port;
    private String host;

    private Handler handler;

    public TimeClient(int port, String host, Handler handler) {
        this.port = port;
        this.host = host;
        this.handler = handler;
    }

    public void init() {
        closed = false;

        workerGroup = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.group(workerGroup);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
        bootstrap.option(ChannelOption.TCP_NODELAY, true);
        bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);

        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addLast(new TimeClientHandler(handler));
            }

            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                super.exceptionCaught(ctx, cause);
                LogUtil.i("TimeClient exceptionCaught 885656-->");
                if (handler != null) {
                    Message message = new Message();
                    message.what = RequestCode.REQUEST_CODE_ERROR;
                    message.obj = "connection error";
                    handler.sendMessage(message);
                }
            }
        });

        doConnect();
    }

    public void doConnect() {
        if (closed) {
            return;
        }

        LogUtil.i("TimeClient doConnect-->");

        ChannelFuture future = null;
        try {
//        future = bootstrap.connect(new InetSocketAddress(host, port));
            future = bootstrap.connect(host, port).sync().addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    LogUtil.i("TimeClient operationComplete-->" + channelFuture.isSuccess());
                    if (channelFuture.isSuccess()) {
                        LogUtil.i("Started Tcp Client: " + getServerInfo());
                    } else {
                        LogUtil.i("Started Tcp Client Failed: " + getServerInfo());
                        channelFuture.channel().eventLoop().schedule(new Runnable() {

                            @Override
                            public void run() {
                                LogUtil.i("operationComplete run-->");
                                try {
                                    doConnect();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }, 1, TimeUnit.SECONDS);
                    }
                }
            });

            future.channel().closeFuture().sync().addListener(new GenericFutureListener<Future<? super Void>>() {
                @Override
                public void operationComplete(Future<? super Void> future) throws Exception {
                    LogUtil.i("TimeClient InterruptedException 252-->");
                }
            });
        } catch (InterruptedException e) {
            e.printStackTrace();
            LogUtil.i("TimeClient InterruptedException-->" + e.getMessage());
        } finally {
            LogUtil.i("TimeClient finally-->");

            workerGroup.shutdownGracefully();
        }
    }

    public void close() {
        closed = true;
        workerGroup.shutdownGracefully();
        LogUtil.i("Stopped Tcp Client: " + getServerInfo());
    }

    private String getServerInfo() {
        return String.format("RemoteHost=%s RemotePort=%d", port, host);
    }

//    public void connect() throws Exception {
//        try {
//            Bootstrap b = new Bootstrap();
//            b.group(workerGroup).channel(NioSocketChannel.class)
//                    .option(ChannelOption.SO_KEEPALIVE, true)
//                    .option(ChannelOption.TCP_NODELAY, true)
//                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
//                    .handler(new ChannelInitializer<SocketChannel>() {
//                        @Override
//                        public void initChannel(SocketChannel ch) throws Exception {
////                            ByteBuf delimiter = Unpooled.copiedBuffer("$"
////                                    .getBytes());
////                            ch.pipeline().addLast(
////                                    new DelimiterBasedFrameDecoder(1024,
////                                            delimiter));
////                            ch.pipeline().addLast(new StringDecoder());
////                            ch.pipeline().addLast(new StringDecoder(Charset.forName("GBK")));
//////                            ch.pipeline().addLast(new StringEncoder(Charset.forName("UTF-8")));
//                            ch.pipeline().addLast(TimeClientHandler.getInstance());
//                        }
//                    });
//
//            // 发起异步连接操作
//            ChannelFuture f = b.connect(host, port).sync().addListener(new ConnectionListener(this));
//
//            // 当代客户端链路关闭
//            f.channel().closeFuture().sync();
//        } finally {
//            // 优雅退出，释放NIO线程组
//            workerGroup.shutdownGracefully();
//        }
//    }
//
//    public class ConnectionListener implements ChannelFutureListener {
//
//        private TimeClient client;
//
//        public ConnectionListener(TimeClient client) {
//            this.client = client;
//        }
//
//        @Override
//        public void operationComplete(ChannelFuture channelFuture) throws Exception {
//            if (!channelFuture.isSuccess()) {
//                LogUtil.i("TimeClient operationComplete-->Reconnect");
//                final EventLoop loop = channelFuture.channel().eventLoop();
//                loop.schedule(new Runnable() {
//
//                    @Override
//                    public void run() {
//                        LogUtil.i("operationComplete run-->");
//                        try {
//                            client.connect();
//                        } catch (Exception e) {
//                            e.printStackTrace();
//                        }
//                    }
//                }, 1L, TimeUnit.SECONDS);
//            }
//        }
//    }
}
